﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using UnityEngine;

/// <summary>
/// Everything帮助类,用于pc端本地快速查找文件。
/// </summary>
namespace Everything
{
    public class EverythingHelper
    {
        const string everything_process_name = "Everything";
        const int bufsize = 260;

        #region EverythingDllImport
        const int EVERYTHING_OK = 0;
        const int EVERYTHING_ERROR_MEMORY = 1;
        const int EVERYTHING_ERROR_IPC = 2;
        const int EVERYTHING_ERROR_REGISTERCLASSEX = 3;
        const int EVERYTHING_ERROR_CREATEWINDOW = 4;
        const int EVERYTHING_ERROR_CREATETHREAD = 5;
        const int EVERYTHING_ERROR_INVALIDINDEX = 6;
        const int EVERYTHING_ERROR_INVALIDCALL = 7;

        [DllImport("Everything32.dll", CharSet = CharSet.Unicode)]
        public static extern int Everything_SetSearchW(string lpSearchString);
        [DllImport("Everything32.dll")]
        public static extern void Everything_SetMatchPath(bool bEnable);
        [DllImport("Everything32.dll")]
        public static extern void Everything_SetMatchCase(bool bEnable);
        [DllImport("Everything32.dll")]
        public static extern void Everything_SetMatchWholeWord(bool bEnable);
        [DllImport("Everything32.dll")]
        public static extern void Everything_SetRegex(bool bEnable);
        [DllImport("Everything32.dll")]
        public static extern void Everything_SetMax(int dwMax);
        [DllImport("Everything32.dll")]
        public static extern void Everything_SetOffset(int dwOffset);

        [DllImport("Everything32.dll")]
        public static extern bool Everything_GetMatchPath();
        [DllImport("Everything32.dll")]
        public static extern bool Everything_GetMatchCase();
        [DllImport("Everything32.dll")]
        public static extern bool Everything_GetMatchWholeWord();
        [DllImport("Everything32.dll")]
        public static extern bool Everything_GetRegex();
        [DllImport("Everything32.dll")]
        public static extern UInt32 Everything_GetMax();
        [DllImport("Everything32.dll")]
        public static extern UInt32 Everything_GetOffset();
        [DllImport("Everything32.dll")]
        public static extern string Everything_GetSearchW();
        [DllImport("Everything32.dll")]
        public static extern int Everything_GetLastError();

        [DllImport("Everything32.dll")]
        public static extern bool Everything_QueryW(bool bWait);

        [DllImport("Everything32.dll")]
        public static extern void Everything_SortResultsByPath();

        [DllImport("Everything32.dll")]
        public static extern int Everything_GetNumFileResults();
        [DllImport("Everything32.dll")]
        public static extern int Everything_GetNumFolderResults();
        [DllImport("Everything32.dll")]
        public static extern int Everything_GetNumResults();
        [DllImport("Everything32.dll")]
        public static extern int Everything_GetTotFileResults();
        [DllImport("Everything32.dll")]
        public static extern int Everything_GetTotFolderResults();
        [DllImport("Everything32.dll")]
        public static extern int Everything_GetTotResults();
        [DllImport("Everything32.dll")]
        public static extern bool Everything_IsVolumeResult(int nIndex);
        [DllImport("Everything32.dll")]
        public static extern bool Everything_IsFolderResult(int nIndex);
        [DllImport("Everything32.dll")]
        public static extern bool Everything_IsFileResult(int nIndex);
        [DllImport("Everything32.dll", CharSet = CharSet.Unicode)]
        public static extern void Everything_GetResultFullPathNameW(int nIndex, StringBuilder lpString, int nMaxCount);
        [DllImport("Everything32.dll")]
        public static extern void Everything_Reset();
        #endregion

        /// <summary>
        /// 查找文件名包含制定字段的本地文件
        /// </summary>
        /// <param name="searchStr">要查找的字段</param>
        /// <param name="path_everything">everything程序的路径</param>
        /// <returns></returns>
        public static StringBuilder StartEverythingSearch(string searchStr,string path_everything)
        {
            //如果指定everything还没有打开，则先打开everything
            if (!IsTheProcessOnRunning(everything_process_name))
            {
                if (File.Exists(path_everything))
                {
                    System.Diagnostics.Process.Start(path_everything);
                }
                else
                {
                    Debug.LogError("没有找到everything程序！");
                    return null;
                }
            }

            //等待程序启动完成
            Thread.Sleep(2000);

            StringBuilder final_string_builder = new StringBuilder();
            StringBuilder buf = new StringBuilder(bufsize);

            StartSearch(searchStr);

            int lastResultsCount = 0;
            int resultsCount = -1;
            resultsCount = Everything_GetNumResults();
            //检测everything是否完全启动，完全启动后才往下面运行
            while (resultsCount <= 0)
            {
                Thread.Sleep(10);
                StartSearch(searchStr);
                resultsCount = Everything_GetNumResults();
            }

            //不断查询结果，直到查到的结果总数不变，即everything已经扫描完了所有的路径
            while (lastResultsCount != resultsCount)
            {
                lastResultsCount = resultsCount;
                Thread.Sleep(500);
                StartSearch(searchStr);
                resultsCount = Everything_GetNumResults();
            }

            //查询完成
            for (int i = 0; i < resultsCount; i++)
            {
                Everything_GetResultFullPathNameW(i, buf, bufsize);
                final_string_builder.Append(buf.ToString());
            }

            return final_string_builder;

        }

        private static void StartSearch(string searchStr)
        {
            Everything_SetSearchW(searchStr);
            Everything_QueryW(true);
        }

        /// <summary>
        /// 指定进程是否存在
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static bool IsTheProcessOnRunning(string name)
        {
            try
            {
                return System.Diagnostics.Process.GetProcessesByName(name).ToList().Count > 0;
            }
            catch
            {
                return false;
            }
        }

    }
}
